#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#include "control.h"
#include "receive_interface.h"
#include "msg_queue.h"
#include "global.h"
#include "face.h"
#include "myoled.h"

#include "ini.h"

#include "gdevice.h"

//定义接收消息结构体，用于封装消息队列中的数据
typedef struct {
    int msg_len;    //消息长度
    unsigned char *buffer;  //消息数据缓冲区
    ctrl_info_t *ctrl_info; //控制信息指针
}recv_msg_t;

//静态全局变量
static int oled_fd = -1;    //OLED显示屏文件描述符
static struct gdevice *pdevhead = NULL; //设备链表头指针

//定义匹配宏，用于简化INI配置项的匹配判断
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0

//INI配置文件处理回调函数
static int handler(void* user, const char* section, const char* name, const char* value)
{
    struct gdevice *pdev = NULL;//临时设备节点指针

    //如果设备链表为空，创建第一个设备节点
    if(NULL == pdevhead)
    {
        pdevhead = (struct gdevice *)malloc(sizeof(struct gdevice));
        pdevhead->next = NULL;
        memset(pdevhead, 0, sizeof(struct gdevice));
        strcpy(pdevhead->dev_name, section);//设置设备名称为节名称
    }
    //如果当前节点名称与链表头设备名称不同，创建新设备线程但并使用头插法
    else if(0 != strcmp(section, pdevhead->dev_name) )
    {
        pdev = (struct gdevice *)malloc(sizeof(struct gdevice));
        memset(pdev, 0, sizeof(struct gdevice));
        strcpy(pdev->dev_name, section);
        pdev->next = pdevhead;//
        pdevhead = pdev;
    }

    //如果设备节点有效，根据配置项名称设置相应属性
    if(NULL != pdevhead)
    {
        //匹配key值配置项
        if(MATCH(pdevhead->dev_name, "key"))
        {
            sscanf(value, "%x", &pdevhead->key);//以十六进制格式解析key值
            printf("%d|pdevhead->key=%x\n", __LINE__, pdevhead->key);
        }
        //匹配gpio_pin配置项
        else if(MATCH(pdevhead->dev_name, "gpio_pin"))
        {
            pdevhead->gpio_pin = atoi(value);//转换为整数
        }
        //匹配gpio_mode配置项
        else if(MATCH(pdevhead->dev_name, "gpio_mode"))
        {
            if(strcmp(value, "OUTPUT") == 0)
            {
                pdevhead->gpio_mode = OUTPUT; //设置为输出模式
            }
            else if(strcmp(value, "INPUT") == 0)
            {
                pdevhead->gpio_mode = INPUT;//设置为输入模式
            } 
        }
        //匹配gpio_status配置项
        else if(MATCH(pdevhead->dev_name, "gpio_status"))
        {
            if(strcmp(value, "LOW") == 0)
            {
                pdevhead->gpio_status = LOW; //设置为低电平
            }
            else if(strcmp(value, "HIGH") == 0)
            {
                pdevhead->gpio_status = HIGH;//设置为高电平
            } 
        }
        //匹配check_face_status配置项
        if(MATCH(pdevhead->dev_name, "check_face_status"))
        {
            pdevhead->check_face_status = atoi(value);//转换为人脸检测状态
        }
        //匹配voice_set_status配置项
        if(MATCH(pdevhead->dev_name, "voice_set_status"))
        {
            pdevhead->voice_set_status = atoi(value);//转换为语音播报状态
        }
    }
    return 1;//返回1表示处理成功
}

//接收接口初始化函数
static int receive_init(void)
{
    //解析设备配置文件/etc/gdevice.ini ARM开发板上路径正确，虚拟机不影响
    if (ini_parse("/etc/gdevice.ini", handler, NULL) < 0) {
        printf("Can't load 'gdevice.ini'\n");
        return 1;
    }

    //打印所有设备配置信息（调试用）
    struct gdevice *pdev = pdevhead;
    while(pdev)
    {
        printf("pdev->dev_name=%s\n", pdev->dev_name);
        printf("pdev->key=%x\n", pdev->key);
        printf("pdev->gpio_pin=%d\n", pdev->gpio_pin);
        printf("pdev->gpio_mode=%d\n", pdev->gpio_mode);
        printf("pdev->gpio_status=%d\n", pdev->gpio_status);
        printf("pdev->check_face_status=%d\n", pdev->check_face_status);
        printf("pdev->voice_set_status=%d\n", pdev->voice_set_status);
        pdev = pdev->next;
        printf("==============================\n");
    }

    oled_fd = myoled_init();//初始化OLED显示屏
    face_init();    //初始化人脸识别模块

    return oled_fd; //返回OLED文件描述符
}

//接收接口结束函数
static void receive_final(void)
{
    face_final();//释放人脸识别模块资源
    if(oled_fd != -1)//关闭OLED显示屏
    {
        close(oled_fd);
        oled_fd = -1;
    }
}

//处理设备控制消息的线程函数
static void *handle_device(void *arg)
{
    recv_msg_t *recv_msg = NULL;    //接收消息指针
    struct gdevice *cur_gdev = NULL;    //当前设备指针
    char success_or_failed[20] = "success"; //操作结果字符串
    int ret = -1;   //操作返回值
    pthread_t tid = -1; //线程ID
    int smoke_status = 0;   //烟雾传感器状态
    double face_result = 0.0;   //人脸识别结果

    //设置线程为分离状态，避免资源泄漏
    pthread_detach(pthread_self() );

    //处理接收到的消息
    if(NULL != arg){
       recv_msg = (recv_msg_t *)arg;
       printf("recv_msg->msg_len = %d\n", recv_msg->msg_len);
       printf("%s|%s|%d:hanle 0x%x, 0x%x,0x%x, 0x%x, 0x%x,0x%x\n",
            __FILE__, __func__, __LINE__, 
            recv_msg->buffer[0], recv_msg->buffer[1],
            recv_msg->buffer[2], recv_msg->buffer[3], 
            recv_msg->buffer[4],recv_msg->buffer[5]);
    }

    //根据消息中的key值查找对应设备
    if(NULL != recv_msg && NULL != recv_msg->buffer)
    {
        cur_gdev = find_gdevice_by_key(pdevhead, recv_msg->buffer[2]);
    }

    //如果找到对应设备，执行控制操作
    if(NULL != cur_gdev)
    {
        //根据消息设置设备状态（LOW/HIGH）
        cur_gdev->gpio_status = recv_msg->buffer[3] == 0 ? LOW : HIGH;

        //特殊处理：对于需要进行人脸识别的设备（如门锁）
        printf("%s|%s|%d:cur_gedv->check_face_status=%d\n",__FILE__, __func__, __LINE__, cur_gdev->check_face_status);
        if(1 == cur_gdev->check_face_status)
        {
            face_result = face_category();//进行人脸识别
            printf("%s|%s|%d:face_result=%f\n",__FILE__, __func__, __LINE__, face_result);
            if(face_result > 0.6){//识别成功阈值
                ret = set_gpio_gdevice_status(cur_gdev);//设置设备状态
                recv_msg->buffer[2] = 0x47;//修改消息内存
            }
            else
            {
                recv_msg->buffer[2] = 0x46;// 失败失败
                ret = -1;
            }
        }
        //普通设备直接设置状态
        else if(0 == cur_gdev->check_face_status)
        {
            ret = set_gpio_gdevice_status(cur_gdev);
        }

        //特殊处理：需要语音播报的设备
        //修复：添加cur_gdev 非空检查
        if(NULL != cur_gdev && 1 == cur_gdev->voice_set_status)
        {
            if(NULL != recv_msg && NULL != recv_msg->ctrl_info && NULL != recv_msg->ctrl_info->ctrl_phead)
            {
                struct control *pcontrol = recv_msg->ctrl_info->ctrl_phead;
                while(NULL != pcontrol)
                {
                    //查找语音控制模块
                    if(strstr(pcontrol->control_name, "voice") )
                    {
                        //特殊处理烟雾报警
                        if(0x45 == recv_msg->buffer[2] && 0 == recv_msg->buffer[3])
                        {                       
                            smoke_status = 1;                        
                        }
                        //创建线程进行语音播报
                        pthread_create(&tid, NULL, pcontrol->set, (void *)recv_msg->buffer);
                        break;
                    }
                    pcontrol = pcontrol->next;//移动到下一个控制模块
                }
            }  
        }

        //根据操作结果设置提示信息
        if(-1 == ret){
            memset(success_or_failed, '\0', sizeof(success_or_failed));
            strncpy(success_or_failed, "failed", 6);
        }

        //准备OLED显示信息
        char oled_msg[512];
        memset(oled_msg, 0, sizeof(oled_msg));

        //修复：添加ccur_gdev 非空检查
        if(NULL != cur_gdev){
            char *change_status = cur_gdev->gpio_status == LOW ? "Open" : "Close";
            sprintf(oled_msg, "%s %s %s!\n", change_status, cur_gdev->dev_name, success_or_failed);
        }else{
            strcpy(oled_msg, "Device not found!\n");
        }

        //特殊处理：烟雾报警显示
        if(smoke_status == 1)
        {
            memset(oled_msg, 0, sizeof(oled_msg) );
            strcpy(oled_msg, "A risk of fire!\n");
        }

        printf("oled_msg=%s\n",oled_msg);
        oled_show(oled_msg);//在OLED上显示信息

        ///特殊处理：门锁自动关闭
        if(1 == cur_gdev->check_face_status && 0 == ret && face_result > 0.6)
        {
            sleep(5);   //延时5秒
            cur_gdev->gpio_status = HIGH;//关闭门锁
            set_gpio_gdevice_status(cur_gdev);
        }

        //修复：只释放buffer,不释放recv_msg 结构体本身
        //因为recv_msg 是在receive_get 中分配并在多个地方使用的
        if(recv_msg && recv_msg->buffer){
            free(recv_msg->buffer);
            recv_msg->buffer = NULL; //防止悬空指针
        }
    }

    pthread_exit(0);    //线程正常退出
}

//接收消息队列数据的线程函数
static void* receive_get(void *arg)
{
    ctrl_info_t *ctrl_info = (ctrl_info_t *)arg;  // 正确获取传入的参数

    recv_msg_t *recv_msg = NULL;    //接收消息结构体指针
    ssize_t read_len = -1;      //读取长度
    pthread_t tid = -1;         //线程ID
    char *buffer = NULL;        //临时缓冲区
    struct mq_attr attr;        //消息队列属性

    if(NULL == ctrl_info){  // 检查参数是否为空
        pthread_exit(0);
    }

    //分配接收消息结构体
    if(NULL != arg){
        recv_msg = (recv_msg_t *)malloc(sizeof(recv_msg_t));
        recv_msg->ctrl_info = (ctrl_info_t *)arg; //获取到mqd 和phead (structcontrol 链表的头结点)
        recv_msg->msg_len = -1;
        recv_msg->buffer = NULL;
    }
    else{
        pthread_exit(0);
    }

    //获取消息队列属性
    if(mq_getattr(recv_msg->ctrl_info->mqd, &attr) == -1)
    {
        pthread_exit(0);
    } 

    //分配缓冲区内存
    recv_msg->buffer = (unsigned char *)malloc(attr.mq_msgsize);
    buffer = (unsigned char *)malloc(attr.mq_msgsize);
    memset(recv_msg->buffer, 0, attr.mq_msgsize);
    memset(buffer, 0, attr.mq_msgsize);
    pthread_detach( pthread_self() );//设置线程为分离状态
    struct timespec timeout = { .tv_sec = 5, .tv_nsec = 0 };

    //循环接收消息队列中的数据
    while(1){
        //从消息队列接收数据
        //read_len = mq_receive(recv_msg->ctrl_info->mqd, buffer,attr.mq_msgsize, NULL);
        read_len = mq_timedreceive(recv_msg->ctrl_info->mqd, buffer,attr.mq_msgsize, NULL, &timeout);
        
        printf("%s|%s|%d:send 0x%x, 0x%x,0x%x, 0x%x, 0x%x,0x%x\n",
            __FILE__, __func__, __LINE__,
            buffer[0], buffer[1], buffer[2], buffer[3],buffer[4],buffer[5]);
        printf("%s|%s|%d:read_len=%ld\n", __FILE__, __func__, __LINE__, read_len);
        
        //处理接收错误
        if(-1 == read_len){
            if(errno == EAGAIN){
                printf("queue is empty\n");
            }
            else if(errno == ETIMEDOUT){
                printf("timeout\n");
                continue;
            }
            else{
                break;
            }
        }
        //处理有效消息（检查消息头尾标识）
        else if(buffer[0] == 0xAA && buffer[1] == 0x55
             && buffer[5] == 0xAA && buffer[4] == 0x55)
        {
            //为每个消息创建独立的结构体
            recv_msg_t *recv_msg = (recv_msg_t *)malloc(sizeof(recv_msg_t));//
            recv_msg->ctrl_info = ctrl_info;//设置控制信息
            recv_msg->msg_len = read_len;   //设置消息长度
            recv_msg->buffer = (unsigned char *)malloc(attr.mq_msgsize);//
            memcpy(recv_msg->buffer, buffer, read_len);//复制消息数据

            //创建线程处理设备控制
            pthread_create(&(tid), NULL, handle_device, (void *)recv_msg);
            pthread_detach(tid);//设置分离状态，避免线程资源泄漏
        }
    }

    //释放临时缓冲区
    if(buffer) {
        free(buffer);
    }

    pthread_exit(0);//线程正常退出
}

//定义接收控制模块结构体实例
struct control receive_control = {
    .control_name = "receive",  //控制模块名称
    .init = receive_init,       //初始化函数
    .final = receive_final,     //结束函数
    .get = receive_get,         //数据接收函数（线程主函数）
    .set = NULL,                //设置函数（未使用）
    .next = NULL                //链表指针
};

//将接收控制模块添加到控制链表中
struct control *add_receive_to_ctrl_list(struct control *phead)
{   
    //使用头插法将接收控制模块添加到链表中
    return add_interface_to_ctrl_list(phead, &receive_control);
};